/*
#include <opencv2/core/core_c.h>
#include <opencv2/imgcodecs/legacy/constants_c.h>
#include <opencv2/imgcodecs/imgcodecs_c.h>
*/
#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>


int main() {
    /*
    IplImage* pImg = cvLoadImage("/home/xlll/Downloads/opencv/samples/data/apple.jpg", CV_LOAD_IMAGE_COLOR);
    */

    /*
    cv::Mat img = cv::imread("/home/xlll/Downloads/opencv/samples/data/apple.jpg", cv::IMREAD_COLOR);
    if (img.empty()) {
        std::cout << "Failed to read image!" << std::endl;
        return EXIT_FAILURE;
    }

    std::cout << "flags = " << std::hex << img.flags << std::endl;
    std::cout << "dims = " << img.dims << std::endl;
    std::cout << "rows = " << img.rows << std::endl;
    std::cout << "cols = " << img.cols << std::endl;

    int isMagic = (img.flags & cv::Mat::MAGIC_MASK) == cv::Mat::MAGIC_VAL;
    std::cout << "is magic = " << isMagic << std::endl;
    int channels = ((img.flags & cv::Mat::TYPE_MASK) >> 3) + 1;
    std::cout << "channels = " << channels << std::endl;
    int depth = img.flags & cv::Mat::DEPTH_MASK;
    std::cout << "depth = " << depth << std::endl;
    int isContinuous = (img.flags & cv::Mat::CONTINUOUS_FLAG) >> 14;
    std::cout << "is continuous = " << isContinuous << std::endl;
    int isSubmatrix = (img.flags & cv::Mat::SUBMATRIX_FLAG) >> 15;
    std::cout << "is submatrix = " << isSubmatrix << std::endl;
    int type = img.flags & cv::Mat::TYPE_MASK - 8;
    std::cout << "type = " << type << std::endl;

    std::cout << "channels() = " << img.channels() << std::endl;
    std::cout << "depth() = " << img.depth() << std::endl;
    std::cout << "isContinuous() = " << img.isContinuous() << std::endl;
    std::cout << "isSubmatrix() = " << img.isSubmatrix() << std::endl;
    std::cout << "type() = " << img.type() << std::endl;
    */

    /*
    cv::Mat mat(2, 3, CV_64FC3, cv::Scalar(1.2, 3.4, 5.6));
    std::cout << "mat = " << std::endl << mat << std::endl;
    std::cout << "rows = " << mat.rows << std::endl;
    std::cout << "cols = " << mat.cols << std::endl;
    std::cout << "channels = " << mat.channels() << std::endl;
    std::cout << "depth = " << mat.depth() << std::endl;

    std::cout << "total = " << mat.total() << std::endl;
    std::cout << "total0 = " << mat.total(0, 1) << std::endl;
    std::cout << "total1 = " << mat.total(1, 2) << std::endl;
    std::cout << "step0 = " << mat.step1(0) << std::endl;
    std::cout << "step1 = " << mat.step1(1) << std::endl;
    std::cout << "elemSize = " << mat.elemSize() << std::endl;
    std::cout << "elemSize1 = " << mat.elemSize1() << std::endl;
    */

    /*
    cv::Mat mat = (cv::Mat_<double>(2, 3) << 1, 2, 3, 4, 5, 6);
    std::cout << "mat ref count = " << mat.u->refcount << std::endl;  // 1
    cv::Mat a, b, c, d(mat);
    std::cout << "mat ref count = " << mat.u->refcount << std::endl;  // 2
    std::cout << "d ref count = " << d.u->refcount << std::endl;  // 2
    a = d;
    b = mat.clone();
    mat.copyTo(c);
    std::cout << "mat ref count = " << mat.u->refcount << std::endl;  // 3
    std::cout << "a ref count = " << a.u->refcount << std::endl;  // 3
    std::cout << "b ref count = " << b.u->refcount << std::endl;  // 1
    std::cout << "c ref count = " << c.u->refcount << std::endl;  // 1

    std::cout << "mat = " << std::endl << mat << std::endl;
    mat.row(1) = mat.row(0) + mat.row(1);
    std::cout << "mat = " << std::endl << mat << std::endl;
    std::cout << "d = " << std::endl << d << std::endl;
    mat.col(1) = mat.col(2);  // not work
    std::cout << "a = " << std::endl << a << std::endl;
    mat.col(2).copyTo(mat.col(1));
    std::cout << "a = " << std::endl << a << std::endl;
    std::cout << "mat ref count = " << mat.u->refcount << std::endl;  // 3

    cv::Mat roi(mat, cv::Rect(0, 0, 2, 1));
    roi = cv::Scalar(0);
    std::cout << "mat = " << std::endl << mat << std::endl;
    std::cout << "mat ref count = " << mat.u->refcount << std::endl;  // 4

    cv::Mat r = mat(cv::Range(0, 1), cv::Range(1, 3));
    cv::Size size;
    cv::Point pt;
    r.locateROI(size, pt);
    std::cout << "mat ref count = " << mat.u->refcount << std::endl;  // 5
    std::cout << "size = " << size << std::endl;  // width x height = 3 x 2, size of the whole matrix
    std::cout << "point = " << pt << std::endl;  // x = 1, y = 0
    */

    /*
    cv::Mat m1(2, 2, CV_8UC3, cv::Scalar(100, 101, 102));
    std::cout << "m1 = \n" << m1 << std::endl;

    cv::Mat m2;
    m2.create(3, 4, CV_32FC2);
    std::cout << "m2 = \n" << m2 << std::endl;

    cv::Mat m3 = cv::Mat::eye(4, 4, CV_64FC4);
    std::cout << "m3 = \n" << m3 << std::endl;

    cv::Mat m4 = cv::Mat::ones(2, 3, CV_8UC1);
    std::cout << "m4 = \n" << m4 << std::endl;

    cv::Mat m5 = cv::Mat::zeros(3, 2, CV_16SC2);
    std::cout << "m5 = \n" << m5 << std::endl;

    cv::Mat m6 = (cv::Mat_<double>(4, 4) << 0, 1, 2, 4, 5, 6, 7, 2, 3, 4, 3, 2, 8, 9, 7, 5);
    std::cout << "m6 = \n" << m6 << std::endl;

    cv::Mat m7 = m6.row(1).clone();
    std::cout << "m7 = \n" << m7 << std::endl;

    cv::Mat m8 = m6.col(3).clone();
    std::cout << "m8 = \n" << m8 << std::endl;

    cv::Mat m9;
    m6.copyTo(m9);
    std::cout << "m9 = \n" << m9 << std::endl;

    cv::Mat m10 = cv::Mat(3, 2, CV_8UC3);
    cv::randu(m10, cv::Scalar::all(0), cv::Scalar::all(255));
    std::cout << "m10 = \n" << m10 << std::endl;
    */

    /*
    cv::Mat mat = (cv::Mat_<uchar>(3, 3) << 0, 1, 2, 3, 4, 5, 6, 7, 8);
    std::cout << "original --> \n" << mat << std::endl;
    int rows = mat.rows;
    int cols = mat.cols;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            mat.at<uchar>(i, j) += 1;
        }
    }
    std::cout << "at --> \n" << mat << std::endl;

    cv::Mat_<uchar> mat_ = mat;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            mat_(i, j) += 1;
        }
    }
    std::cout << "Mat_() --> \n" << mat << std::endl;

    for (int i = 0; i < rows; i++) {
        uchar* p = mat.ptr<uchar>(i);
        for (int j = 0; j < cols; j++) {
            p[j] += 1;
        }
    }
    std::cout << "ptr --> \n" << mat << std::endl;

    if (mat.isContinuous()) {
         uchar* data = mat.data;
        for (int i = 0; i < rows*cols; i++) {
            data[i] += 1;
        }
    }
    std::cout << "data --> \n" << mat << std::endl;

    cv::MatIterator_<uchar> it, end;
    for (it = mat.begin<uchar>(), end = mat.end<uchar>(); it != end; ++it) {
        *it += 1;
    }
    std::cout << "MatIterator_ --> \n" << mat << std::endl;

    std::cout << "==============================================" << std::endl;

    cv::Mat mat3c;
    mat3c.create(2, 2, CV_8UC3);
    rows = mat3c.rows;
    cols = mat3c.cols;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            mat3c.at<cv::Vec3b>(i, j)[0] = i*2*3+j*3;
            mat3c.at<cv::Vec3b>(i, j)[1] = i*2*3+j*3+1;
            mat3c.at<cv::Vec3b>(i, j)[2] = i*2*3+j*3+2;
        }
    }
    std::cout << "original 3c, at --> \n" << mat3c << std::endl;

    cv::Mat_<cv::Vec3b> mat3c_ = mat3c;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            mat3c_(i, j)[0] += 1;
            mat3c_(i, j)[1] += 1;
            mat3c_(i, j)[2] += 1;
        }
    }
    std::cout << "3c Mat_() --> \n" << mat3c << std::endl;

    for (int i = 0; i < rows; i++) {
        cv::Vec3b* p = mat3c.ptr<cv::Vec3b>(i);
        for (int j = 0; j < cols; j++) {
            p[j][0] += 1;
            p[j][1] += 1;
            p[j][2] += 1;
        }
    }
    std::cout << "3c ptr --> \n" << mat3c << std::endl;

    if (mat3c.isContinuous()) {
        uchar* data = mat3c.data;
        for (int i = 0; i < rows*cols; i++) {
            data[i*3] += 1;
            data[i*3+1] += 1;
            data[i*3+2] += 1;
        }
    }
    std::cout << "3c data -->\n" << mat3c << std::endl;

    cv::MatIterator_<cv::Vec3b> it3c, end3c;
    for (it3c = mat3c.begin<cv::Vec3b>(), end3c = mat3c.end<cv::Vec3b>(); it3c != end3c; ++it3c) {
        (*it3c)[0] += 1;
        (*it3c)[1] += 1;
        (*it3c)[2] += 1;
    }
    std::cout << "3c MatIterator_ --> \n" << mat3c << std::endl;
    */

    cv::Mat mat(2, 3, CV_8UC3);
    cv::randu(mat, cv::Scalar::all(0), cv::Scalar::all(255));
    std::cout << "default:\n" << mat << std::endl;
    std::cout << "python format:\n" << cv::format(mat, cv::Formatter::FMT_PYTHON) << std::endl;
    std::cout << "csv format:\n" << cv::format(mat, cv::Formatter::FMT_CSV) << std::endl;
    std::cout << "numpy format:\n" << cv::format(mat, cv::Formatter::FMT_NUMPY) << std::endl;
    std::cout << "c format:\n" << cv::format(mat, cv::Formatter::FMT_C) << std::endl;
    std::cout << "default format: \n" << cv::format(mat, cv::Formatter::FMT_DEFAULT) << std::endl;
    std::cout << "matlab format:\n" << cv::format(mat, cv::Formatter::FMT_MATLAB) << std::endl;

    return EXIT_SUCCESS;
}
